/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.tewi.contexts;

import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.List;
import javax.ejb.EJB;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pl.tewi.exceptions.InjectionException;
import pl.tewi.utils.AnnotationUtils;

/**
 * Wstrzykuje w pola przekazanego obiektu referencje do obiektów komponentów ejb
 * pobranych z serwera aplikacyjnego. Test w projekcie zewnątrznym JeeUnitTest
 * @author Marcin Kwapisz
 */
public class EjbFieldInjector implements FieldInjector {

    /**
     * Logger
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(EjbFieldInjector.class);

    /**
     * Wstrzykuje w pole obiektu komponent ejb na podstawie typu pola opisanego 
     * adnotacją @EJB. Metoda przeszukuje aplikacje skonfigurowane dla tego 
     * kontekstu serwera apliakcyjnego
     * @param test obiekt testu
     * @param initialContext kontekst do przeszukwiania jndi serwera aplikacyjnego
     * @param applicationServerContext kontekst narzędzia dla serwera aplikacyjnego
     * @throws InjectionException błąd wstrzykiwania zależności
     */
    @Override
    public void inject(final Object test, final InitialContext initialContext, final ApplicationServerContext applicationServerContext) throws InjectionException {
        try {
            List<Field> annotatedFileds = AnnotationUtils.getAnnotatedFileds(test.getClass(), EJB.class);
            //Nazwa hosta i port nie mają znaczenia w przypadku serwera wbudowanego.
            Object ejb = null;
            List<String> jndiContexts = applicationServerContext.getJNDIBaseContextPath();

            for (Field annotatedFiled : annotatedFileds) {
                EJB ejbAnnotation = annotatedFiled.getAnnotation(EJB.class);
                String beanName = ejbAnnotation.beanName();
                //Pobiera bazowe konteksty wszystkich skonfigurowanych aplikacji i przeszukuje je
                Iterator<String> iter = jndiContexts.iterator();
                String jndiContext, jndiName;
                while (iter.hasNext()) {
                    try {
                        jndiContext = iter.next();
                        jndiName = jndiContext + beanName;
                        ejb = initialContext.lookup(jndiName);
                        LOGGER.debug("Injecting EJB ({}) component", jndiName);
                        annotatedFiled.set(test, ejb);
                        //zakończ po znalezieniu pierwszego pasujacego
                        break;
                    } catch (NamingException ne) {
                        //ignoruj wszystkie błędy do momentuy przeszukania wszystkich kontekstów jndi
                        if (!iter.hasNext()) {
                            LOGGER.error("Name not found {}", beanName);
                            throw new InjectionException(InjectionException.NAME_NOT_FOUND, ne);
                        }
                    }
                }
            }
        } catch (IllegalArgumentException ex) {
            LOGGER.error(null, ex);
            throw new InjectionException(ex);
        } catch (IllegalAccessException ex) {
            LOGGER.error("Unaccessible field", ex);
            throw new InjectionException(InjectionException.REFLECTION_UNACCESSIBLE_FILED, ex);
        }
    }
}

